package jp.co.technotree.common.util;

import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class ObjectUtil {
	/**
	 * オブジェクト文字列化ユーティリティ
	 * @param target 対象シリアライザブルオブジェクト
	 * @return 符号化文字列
	 * @throws IOException
	 */
	public static String createSerializableTextFromObject(Serializable target) throws IOException{
		BASE64Encoder encoder = null;
		ByteArrayOutputStream baos = null;
		ObjectOutputStream oos = null;
		byte[] byteArray = null;
		byte[] zip_byteArray = null;
		String dataString = null;
		
		encoder = new BASE64Encoder();
		
		baos = new ByteArrayOutputStream();
		oos = new ObjectOutputStream(baos);
		oos.writeObject(target);
		byteArray = baos.toByteArray();
		
		oos.close();
		baos.close();
		oos = null;
		baos = null;

		zip_byteArray = gzipCompress(byteArray);
		
		dataString = encoder.encode(zip_byteArray);

		byteArray = null;
		encoder = null;
		zip_byteArray = null;
		
		return dataString;
	}
	
	/**
	 * オブジェクト文字列化ユーティリティ
	 * @param serializableText
	 * @return 復号オブジェクト
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static Object createObjectFromSerializableText(String serializableText) throws IOException, ClassNotFoundException{
		BASE64Decoder decoder = new BASE64Decoder();
		ByteArrayInputStream bais = null;
		ObjectInputStream getObject = null;
		byte[] byteArray = null;
		byte[] resultArray = null;
		
		byteArray = decoder.decodeBuffer(serializableText);
		resultArray = gzipDecompress(byteArray);
		
		bais = new ByteArrayInputStream(resultArray);
		getObject = new ObjectInputStream(bais);
		Object resultObject = getObject.readObject();
		getObject.close();
		bais.close();
		
		getObject = null;
		bais = null;
		
		return resultObject;
	}
	
	
	
	
	/**
	 * バイト配列圧縮ユーティリティ
	 * @param byteArray 圧縮対象バイト配列
	 * @return 圧縮済みバイト配列
	 * @throws IOException
	 */
	public static byte[] gzipCompress(byte[] byteArray) throws IOException{
		ByteArrayOutputStream byteArrayOutputStream = null;
		GZIPOutputStream gzipOutputStream = null;
		byte[] resultArray = null;
		
		byteArrayOutputStream = new ByteArrayOutputStream();
		gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
		
		gzipOutputStream.write(byteArray,0,byteArray.length);
		gzipOutputStream.flush();
		gzipOutputStream.close();
		gzipOutputStream = null;
		
		resultArray = byteArrayOutputStream.toByteArray();
		
		byteArrayOutputStream.close();
		byteArrayOutputStream = null;
		
		return resultArray;
	}
	
	/**
	 * 圧縮済みバイト配列展開ユーティリティ
	 * @param byteArray 圧縮済みバイト配列
	 * @return 展開済みバイト配列
	 * @throws IOException
	 */
	public static byte[] gzipDecompress(byte[] byteArray) throws IOException{
		ByteArrayOutputStream byteArrayOutputStream = null;
		byte[] resultArray = null;
		ByteArrayInputStream byteArrayInputStream = null;
		GZIPInputStream gzipInputStream = null;
		byte[] recvBuffer = null;
		int recvSize = 0;
		
		byteArrayOutputStream = new ByteArrayOutputStream();
		
		byteArrayInputStream = new ByteArrayInputStream(byteArray);
		gzipInputStream = new GZIPInputStream(byteArrayInputStream);
		recvBuffer = new byte[1024];
		
		while ( true ){
			recvSize = gzipInputStream.read(recvBuffer,0,recvBuffer.length);
			if ( recvSize <= 0 ) break;
			byteArrayOutputStream.write(recvBuffer,0,recvSize);
		}
		byteArrayOutputStream.flush();
		resultArray = byteArrayOutputStream.toByteArray();
		
		recvBuffer = null;
		
		byteArrayInputStream.close();
		gzipInputStream.close();
		byteArrayOutputStream.close();
		
		byteArrayInputStream = null;
		gzipInputStream = null;
		byteArrayOutputStream = null;
		
		return resultArray;

	}
	
	private static Calendar toCalendar(String strDate) {
		strDate = format(strDate);
		Calendar cal = Calendar.getInstance();

		int yyyy = Integer.parseInt(strDate.substring(0, 4));
		int MM = Integer.parseInt(strDate.substring(5, 7));
		int dd = Integer.parseInt(strDate.substring(8, 10));
		int HH = cal.get(Calendar.HOUR_OF_DAY);
		int mm = cal.get(Calendar.MINUTE);
		int ss = cal.get(Calendar.SECOND);
		int SSS = cal.get(Calendar.MILLISECOND);

		cal.clear();
		cal.set(yyyy, MM - 1, dd);

		int len = strDate.length();
		switch (len) {
		case 10:
			break;
		case 16: // yyyy/MM/dd HH:mm
			HH = Integer.parseInt(strDate.substring(11, 13));
			mm = Integer.parseInt(strDate.substring(14, 16));
			cal.set(Calendar.HOUR_OF_DAY, HH);
			cal.set(Calendar.MINUTE, mm);
			break;
		case 19: // yyyy/MM/dd HH:mm:ss
			HH = Integer.parseInt(strDate.substring(11, 13));
			mm = Integer.parseInt(strDate.substring(14, 16));
			ss = Integer.parseInt(strDate.substring(17, 19));
			cal.set(Calendar.HOUR_OF_DAY, HH);
			cal.set(Calendar.MINUTE, mm);
			cal.set(Calendar.SECOND, ss);
			break;
		case 23: // yyyy/MM/dd HH:mm:ss.SSS
			HH = Integer.parseInt(strDate.substring(11, 13));
			mm = Integer.parseInt(strDate.substring(14, 16));
			ss = Integer.parseInt(strDate.substring(17, 19));
			SSS = Integer.parseInt(strDate.substring(20, 23));
			cal.set(Calendar.HOUR_OF_DAY, HH);
			cal.set(Calendar.MINUTE, mm);
			cal.set(Calendar.SECOND, ss);
			cal.set(Calendar.MILLISECOND, SSS);
			break;
		default:
			throw new IllegalStateException("このString文字列は日付文字列に変換できません : "
					+ strDate);
		}
		return cal;
	}

	/**
	 * あらゆる日付文字列を"yyyy/MM/dd" or "yyyy/MM/dd HH:mm:ss"の フォーマットに変換することを試みます。
	 * 例：03/1/3 ⇒ 2003/01/03
	 * @param strDate
	 * @return
	 */
	public static String format(String strDate) {
		strDate = strDate.trim();
		String yyyy = null;
		String MM = null;
		String dd = null;
		String HH = null;
		String mm = null;
		String ss = null;
		String SSS = null;

		// "-" or "/" が無い場合
		if (strDate.indexOf("/") == -1 && strDate.indexOf("-") == -1) {
			if (strDate.length() == 8) {
				yyyy = strDate.substring(0, 4);
				MM = strDate.substring(4, 6);
				dd = strDate.substring(6, 8);
				return yyyy + "/" + MM + "/" + dd;
			} else {
				yyyy = strDate.substring(0, 4);
				MM = strDate.substring(4, 6);
				dd = strDate.substring(6, 8);
				HH = strDate.substring(9, 11);
				mm = strDate.substring(12, 14);
				ss = strDate.substring(15, 17);
				return yyyy + "/" + MM + "/" + dd + " " + HH + ":" + mm + ":"
						+ ss;
			}
		}
		StringTokenizer token = new StringTokenizer(strDate, "_/-:. ");
		StringBuffer result = new StringBuffer();
		for (int i = 0; token.hasMoreTokens(); i++) {
			String temp = token.nextToken();
			switch (i) {
			case 0:// 年の部分
				yyyy = fillString(strDate, temp, "f", "20", 4);
				result.append(yyyy);
				break;
			case 1:// 月の部分
				MM = fillString(strDate, temp, "f", "0", 2);
				result.append("/" + MM);
				break;
			case 2:// 日の部分
				dd = fillString(strDate, temp, "f", "0", 2);
				result.append("/" + dd);
				break;
			case 3:// 時間の部分
				HH = fillString(strDate, temp, "f", "0", 2);
				result.append(" " + HH);
				break;
			case 4:// 分の部分
				mm = fillString(strDate, temp, "f", "0", 2);
				result.append(":" + mm);
				break;
			case 5:// 秒の部分
				ss = fillString(strDate, temp, "f", "0", 2);
				result.append(":" + ss);
				break;
			case 6:// ミリ秒の部分
				SSS = fillString(strDate, temp, "b", "0", 3);
				result.append("." + SSS);
				break;
			}
		}
		return result.toString();
	}
	private static String fillString(String strDate, String str,
			String position, String addStr, int len) {

		if (str.length() > len) {
			String mes = strDate + "このString文字列は日付文字列に変換できません";
			throw new IllegalStateException(mes);
		}
		return fillString(str, position, addStr, len);
	}
	/**
	 * 文字列[str]に対して補充する文字列[addStr]を[position]の位置に[len]に 満たすまで挿入します。
	 * 
	 * 例： String ss = StringUtil.fillString("aaa","b","0",7); ss ⇒ "aaa0000"
	 * 
	 * ※fillString()はlenに満たすまで挿入しますが、addString()はlen分挿入します。
	 * 
	 * @param str 対象文字列
	 * @param position 前に挿入 ⇒ F/f 後に挿入 ⇒ B/b
	 * @param addStr 挿入する文字列
	 * @param len 補充するまでの桁数
	 * @return 変換後の文字列。 [str]がnullや空リテラルも[addStr]を[len]に 満たすまで 挿入した結果を返します。
	 */
	private static String fillString(String str, String position,
			String addStr, int len) {
		StringBuffer tempBuffer = null;
		if (!isExist(str)) {
			tempBuffer = new StringBuffer();
			for (int i = 0; i < len; i++) {
				tempBuffer.append(addStr);
			}
			return tempBuffer.toString();
		} else if (str.length() != len) {
			tempBuffer = new StringBuffer(str);
			while (len > tempBuffer.length()) {
				if (position.equalsIgnoreCase("f")) {
					tempBuffer.insert(0, addStr);
				} else {
					tempBuffer.append(addStr);
				}
			}
			return tempBuffer.toString();
		}
		return str;
	}
	/**
	 * [value]が有効な値かどうか検証します。
	 * 
	 * @param value 評価対象文字列
	 * @return [true]:nullでなく""でない場合
	 */
	private static boolean isExist(String value) {
		if (value != null && value.length() != 0) {
			return true;
		}
		return false;
	}

	
	public static Color getColor(int index){
		switch(index%10){
		case 0:
			return Color.BLUE;
		case 1:
			return Color.CYAN;
		case 2:
			return Color.GREEN;
		case 3:
			return Color.MAGENTA;
		case 4:
			return Color.ORANGE;
		case 5:
			return Color.PINK;
		case 6:
			return Color.RED;
		case 7:
			return Color.BLACK;
		case 8:
			return Color.YELLOW;
		case 9:
			return Color.DARK_GRAY;
		}
		return Color.BLACK;
	}
	
	// intから16進2桁に変換
	public static String IntToHex2(int Value) {
	    char HEX2[]= {Character.forDigit((Value>>4) & 0x0F,16),
	    Character.forDigit(Value & 0x0F,16)};
	    String Hex2Str = new String(HEX2);
	    return Hex2Str.toUpperCase();
	}

	// intから16進4桁に変換
	public static String IntToHex4(int Value) {
	    char HEX4[]= {Character.forDigit((Value>>12) &
	        0x0F,16),Character.forDigit((Value>>8) & 0x0F,16)
	        ,Character.forDigit((Value>>4) & 0x0F,16),Character.
	        forDigit(Value & 0x0F,16)};
	    String Hex4Str = new String(HEX4);
	    return Hex4Str.toUpperCase();
	}
}
